//  初始化着色器程序，让 WebGL 知道如何绘制我们的数据
function initShaderProgram(gl, vsSource, fsSource) {
	const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource);
	const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource);

	// 创建着色器程序

	const shaderProgram = gl.createProgram();
	gl.attachShader(shaderProgram, vertexShader);
	gl.attachShader(shaderProgram, fragmentShader);
	gl.linkProgram(shaderProgram);

	// 如果创建失败，alert
	if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
		alert(
			"Unable to initialize the shader program: " +
			gl.getProgramInfoLog(shaderProgram),
		);
		return null;
	}

	return shaderProgram;
}

//
// 创建指定类型的着色器，上传 source 源码并编译
//
function loadShader(gl, type, source) {
	const shader = gl.createShader(type);

	// Send the source to the shader object

	gl.shaderSource(shader, source);

	// Compile the shader program

	gl.compileShader(shader);

	// See if it compiled successfully

	if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
		alert(
			"An error occurred compiling the shaders: " + gl.getShaderInfoLog(shader),
		);
		gl.deleteShader(shader);
		return null;
	}

	return shader;
}






function main() {
	const canvas = document.querySelector("#glcanvas");

	const gl = canvas.getContext("webgl2");


	if (!gl) {
		alert("无法初始化 WebGL2，你的浏览器、操作系统或硬件等可能不支持 WebGL2。");
		return;
	}

	gl.viewport(0, 0, screen_width, screen_height);

	gl.clearColor(0.0, 0.0, 0.0, 1.0);

	gl.clear(gl.COLOR_BUFFER_BIT);
	//关闭混合
	//gl.enable(gl.BLEND);
	//gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
	gl.enable(gl.DEPTH_TEST); // Enable depth testing
	gl.depthFunc(gl.LEQUAL); // Near things obscure far things

	const default_framebuffer = gl.getParameter(gl.FRAMEBUFFER_BINDING);

	//使用拓展
	const ext = gl.getExtension("EXT_color_buffer_float");


	//用于HDR的帧缓冲
	let FBO_hdr_full_size = gl.createFramebuffer();
	let tex_hdr_full_size = gl.createTexture();
	//纹理
	gl.bindTexture(gl.TEXTURE_2D, tex_hdr_full_size);
	gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA16F, screen_width, screen_height, 0, gl.RGBA, gl.FLOAT, null);//*********************
	gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
	gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
	//深度缓冲
	let dep_hdr_full_size = gl.createRenderbuffer();
	gl.bindRenderbuffer(gl.RENDERBUFFER, dep_hdr_full_size);
	gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, screen_width, screen_height);

	gl.bindFramebuffer(gl.FRAMEBUFFER, FBO_hdr_full_size);
	gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex_hdr_full_size, 0);
	gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, dep_hdr_full_size);
	if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) !== gl.FRAMEBUFFER_COMPLETE) {
		alert("Framebuffer not complete!");
	}


	const num_framebuffer = 4;
	//用于dual blur的帧缓冲
	let FBO_hdr = [];
	let tex_hdr = [];
	let array_span_pixel = [];
	let array_buffer_size = [];
	let buffer_width = screen_width;
	let buffer_height = screen_height;
	for (let i = 0; i < num_framebuffer; i += 1) {
		//用于HDR的帧缓冲
		FBO_hdr[i] = gl.createFramebuffer();
		tex_hdr[i] = gl.createTexture();
		//纹理
		gl.bindTexture(gl.TEXTURE_2D, tex_hdr[i]);
		gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA16F, buffer_width, buffer_height, 0, gl.RGBA, gl.FLOAT, null);//*********************
		gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
		gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
		//深度缓冲
		let dep_hdr = gl.createRenderbuffer();
		gl.bindRenderbuffer(gl.RENDERBUFFER, dep_hdr);
		gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, buffer_width, buffer_height);

		gl.bindFramebuffer(gl.FRAMEBUFFER, FBO_hdr[i]);
		gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex_hdr[i], 0);
		gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, dep_hdr);
		if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) !== gl.FRAMEBUFFER_COMPLETE) {
			alert("Framebuffer not complete!");
		}
		//gl.bindFramebuffer(gl.FRAMEBUFFER, default_framebuffer);

		array_span_pixel[2 * i] = 1.0 / buffer_width;
		array_span_pixel[2 * i + 1] = 1.0 / buffer_height;

		array_buffer_size[2 * i] = buffer_width;
		array_buffer_size[2 * i + 1] = buffer_height;

		buffer_width /= 2;
		buffer_height /= 2;
	}





	//编译链接着色器
	//const shaderProgram_ground = initShaderProgram(gl, vertice_ground_source, fragment_ground_source);
	const shaderProgram_firework = initShaderProgram(gl, vertice_firework_source, fragment_firework_source);
	const shaderProgram_rect = initShaderProgram(gl, vertice_rect_source, fragment_rect_source);
	const shaderProgram_downsample = initShaderProgram(gl, vertice_rect_source, fragment_blur_downsample_source);
	const shaderProgram_upsample = initShaderProgram(gl, vertice_rect_source, fragment_blur_upsample_source);

	//firework顶点属性
	const programInfo_firework = {
		program: shaderProgram_firework,
		attribLocations: {
			vertexPosition: gl.getAttribLocation(shaderProgram_firework, "aPos"),
			instanceDirection: gl.getAttribLocation(shaderProgram_firework, "instance_direction"),
		},
		uniformLocations: {
			oneMatrix: gl.getUniformLocation(shaderProgram_firework, "pers_and_rotate"),//合并透视和旋转矩阵
			//rotateMatrix: gl.getUniformLocation(shaderProgram_firework, "rota"),
			rotate_cMatrix: gl.getUniformLocation(shaderProgram_firework, "rota_c"),
			timeFloat: gl.getUniformLocation(shaderProgram_firework, "time_fire"),
			randColor: gl.getUniformLocation(shaderProgram_firework, "color_firework"),
			randVelocity: gl.getUniformLocation(shaderProgram_firework, "rand_velocity"),
			randPosition: gl.getUniformLocation(shaderProgram_firework, "rand_position"),
			randExplode: gl.getUniformLocation(shaderProgram_firework, "rand_explode"),
			traceSize: gl.getUniformLocation(shaderProgram_firework, "size"),
			seed: gl.getUniformLocation(shaderProgram_firework, "seed"),
		},
	};

	//rect顶点属性
	const programInfo_rect = {
		program: shaderProgram_rect,
		attribLocations: {
			vertexPosition: gl.getAttribLocation(shaderProgram_rect, "aPos_n_texcoord"),
		},
		uniformLocations: {
			hdrTexture: gl.getUniformLocation(shaderProgram_rect, "Tex_hdr"),
			blurTexture: gl.getUniformLocation(shaderProgram_rect, "Tex_blur"),
		},
	};

	//downsample顶点属性
	const programInfo_downsample = {
		program: shaderProgram_downsample,
		attribLocations: {
			vertexPosition: gl.getAttribLocation(shaderProgram_downsample, "aPos_n_texcoord"),
		},
		uniformLocations: {
			hdrTexture: gl.getUniformLocation(shaderProgram_downsample, "Tex_hdr"),
			spanPixel: gl.getUniformLocation(shaderProgram_downsample, "span_pixel"),
		},
	};

	//upsample顶点属性
	const programInfo_upsample = {
		program: shaderProgram_upsample,
		attribLocations: {
			vertexPosition: gl.getAttribLocation(shaderProgram_upsample, "aPos_n_texcoord"),
		},
		uniformLocations: {
			hdrTexture: gl.getUniformLocation(shaderProgram_upsample, "Tex_hdr"),
			spanPixel: gl.getUniformLocation(shaderProgram_upsample, "span_pixel"),
		},
	};



	const num_vertices = 8;
	const num_firework = 5;
	const VAO_firework = VAO_firework_generate(gl, programInfo_firework, num_vertices, num_firework);
	const VAO_rect = VAO_rect_generate(gl, programInfo_rect);



	//激活纹理单元
	// gl.activeTexture(gl.TEXTURE0);
	// gl.bindTexture(gl.TEXTURE_2D, tex_hdr);
	// gl.useProgram(programInfo_rect.program);
	// gl.uniform1i(programInfo_rect.uniformLocations.hdrTexture, 0);

	//表格初始化 颜色表格
	table_add_row("#ff4040");
	table_add_row("#40ff40");
	apply_color_data();


	let then = 0;

	function render(now) {
		//生成随机数
		//const threshold = 0.03;
		const threshold = parseFloat(probability_range.value);
		const rand_firework = Math.random();
		if (rand_firework < threshold) {
			//增加firework
			// let color_firework;
			// if (Math.random() > 0.5) {
			// 	color_firework = [1.1, 1.8, 1.1];
			// } else {
			// 	color_firework = [1.8, 1.1, 1.1];
			// }
			// para_firework.push(color_firework[0], color_firework[1], color_firework[2]);

			// para_firework.push(Math.random());
			// para_firework.push(Math.random());
			// para_firework.push(Math.random());
			// para_firework.push(0);

			add_firework(Math.random());
		}
		//para_firework 过时处理
		if (para_firework[6] > 2) {
			for (let i = 0; i < 7; i += 1) {
				para_firework.shift();
			}
		}


		now *= 0.001; // convert to seconds
		const deltaTime = now - then;
		then = now;

		const perspec = [
			1.0, 0.0, 0.0, 0.0, 0.0, screen_width / screen_height, 0.0, 0.0, 0.0, 0.0, -1.001, -1.0, 0.0, 0.0, -0.21, 0.0];

		const xz_sin = Math.sin(angle_xz);
		const xz_cos = Math.cos(angle_xz);
		const y_sin = Math.sin(angle_y);
		const y_cos = Math.cos(angle_y);
		const rotate = [xz_cos, y_sin * xz_sin, y_cos * xz_sin, 0.0,
			0.0, y_cos, -y_sin, 0.0,
			-xz_sin, y_sin * xz_cos, y_cos * xz_cos, 0.0,
			0.0, 0.0, 0.0, 1.0];
		const rotate_contra = [xz_cos, y_sin * xz_sin, -y_cos * xz_sin, 0.0,
			0.0, y_cos, y_sin, 0.0,
			xz_sin, -y_sin * xz_cos, y_cos * xz_cos, 0.0,
			0.0, 0.0, 0.0, 1.0];

		let pers_and_rotate = mul_matrix(perspec, rotate);

		//从hdr帧缓冲渲染
		gl.bindFramebuffer(gl.FRAMEBUFFER, FBO_hdr_full_size);
		gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

		//渲染firework
		gl.useProgram(programInfo_firework.program);
		gl.uniformMatrix4fv(programInfo_firework.uniformLocations.oneMatrix, false, new Float32Array(pers_and_rotate));
		//gl.uniformMatrix4fv(programInfo_firework.uniformLocations.rotateMatrix, false, new Float32Array(rotate));
		gl.uniformMatrix4fv(programInfo_firework.uniformLocations.rotate_cMatrix, false, new Float32Array(rotate_contra));
		//gl.uniform1f(programInfo_firework.uniformLocations.timeFloat, now % 2);
		gl.bindVertexArray(VAO_firework);
		//循环渲染不同firework
		for (let i = 0; i < para_firework.length; i += 7) {
			gl.uniform1f(programInfo_firework.uniformLocations.timeFloat, para_firework[i + 6]);
			gl.uniform3f(programInfo_firework.uniformLocations.randColor, para_firework[i], para_firework[i + 1], para_firework[i + 2]);
			gl.uniform1f(programInfo_firework.uniformLocations.randVelocity, para_firework[i + 3]);
			gl.uniform1f(programInfo_firework.uniformLocations.randPosition, para_firework[i + 4]);
			gl.uniform1f(programInfo_firework.uniformLocations.randExplode, para_firework[i + 5]);

			gl.uniform1f(programInfo_firework.uniformLocations.seed, para_firework[i + 4] * para_firework[i + 5] * 24567.24);//随机数种子
			gl.uniform1f(programInfo_firework.uniformLocations.traceSize, 1.0);



			if (para_firework[i + 6] < 1) {
				gl.drawElements(gl.TRIANGLES, (num_vertices - 2) * 3, gl.UNSIGNED_SHORT, 0);
			} else {
				gl.drawElementsInstanced(gl.TRIANGLES, (num_vertices - 2) * 3, gl.UNSIGNED_SHORT, 0, num_firework * (num_firework - 1) * 2);

				//轨迹 在特定时间下会有轨迹
				const num_trace = 10;
				const period_trace = 2;
				let time_trace = Math.floor(para_firework[i + 6] * 10.0) / 10.0;

				for (let i_trace = 0; time_trace > 1.0 && i_trace < period_trace; i_trace += 1, time_trace -= 1.0 / num_trace) {
					gl.uniform1f(programInfo_firework.uniformLocations.timeFloat, time_trace);
					let traceSize = (period_trace - (para_firework[i + 6] - time_trace)) / period_trace;
					gl.uniform1f(programInfo_firework.uniformLocations.traceSize, traceSize);
					gl.drawElementsInstanced(gl.TRIANGLES, 3, gl.UNSIGNED_SHORT, 0, num_firework * (num_firework - 1) * 2);

				}

			}




			//时间更新
			para_firework[i + 6] += deltaTime;
		}



		//模糊流程
		//下采样
		for (let i = 0; i < num_framebuffer - 1; i += 1) {
			gl.viewport(0, 0, array_buffer_size[2 * (i + 1)], array_buffer_size[2 * (i + 1) + 1]);
			//绑定默认帧缓冲
			gl.bindFramebuffer(gl.FRAMEBUFFER, FBO_hdr[i + 1]);
			gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

			gl.useProgram(programInfo_downsample.program);
			gl.bindVertexArray(VAO_rect);

			gl.activeTexture(gl.TEXTURE0);
			if (i == 0) {
				gl.bindTexture(gl.TEXTURE_2D, tex_hdr_full_size);
			} else {
				gl.bindTexture(gl.TEXTURE_2D, tex_hdr[i]);
			}

			// gl.useProgram(programInfo_rect.program);
			gl.uniform1i(programInfo_downsample.uniformLocations.hdrTexture, 0);
			gl.uniform2f(programInfo_downsample.uniformLocations.spanPixel, array_span_pixel[2 * i], array_span_pixel[2 * i + 1]);

			gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
		}
		//上采样
		for (let i = num_framebuffer - 1; i > 0; i -= 1) {
			gl.viewport(0, 0, array_buffer_size[2 * (i - 1)], array_buffer_size[2 * (i - 1) + 1]);
			//绑定默认帧缓冲
			gl.bindFramebuffer(gl.FRAMEBUFFER, FBO_hdr[i - 1]);
			gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

			gl.useProgram(programInfo_upsample.program);
			gl.bindVertexArray(VAO_rect);

			gl.activeTexture(gl.TEXTURE0);
			gl.bindTexture(gl.TEXTURE_2D, tex_hdr[i]);
			// gl.useProgram(programInfo_rect.program);
			gl.uniform1i(programInfo_upsample.uniformLocations.hdrTexture, 0);
			gl.uniform2f(programInfo_upsample.uniformLocations.spanPixel, array_span_pixel[2 * i], array_span_pixel[2 * i + 1]);

			gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
		}


		//绑定默认帧缓冲
		gl.bindFramebuffer(gl.FRAMEBUFFER, default_framebuffer);
		gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
		//渲染rect
		gl.useProgram(programInfo_rect.program);
		gl.bindVertexArray(VAO_rect);

		gl.activeTexture(gl.TEXTURE0);
		gl.bindTexture(gl.TEXTURE_2D, tex_hdr_full_size);
		gl.uniform1i(programInfo_rect.uniformLocations.blurTexture, 0);

		gl.activeTexture(gl.TEXTURE1);
		gl.bindTexture(gl.TEXTURE_2D, tex_hdr[0]);
		gl.uniform1i(programInfo_rect.uniformLocations.hdrTexture, 1);

		gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);


		requestAnimationFrame(render);
	}

	requestAnimationFrame(render);
}

let angle_xz = 0;
let angle_y = 0;
let x = 0;
let y = 0;

//const screen_width = 640;
//const screen_height = 480;
//鼠标事件
// function handle_mousemove(event) {
// 	const x_current = event.offsetX;
// 	const y_current = event.offsetY;

// 	if (isclick) {
// 		angle_xz += (x_current - x) / screen_width * Math.PI / 2.0;
// 		angle_y += (y_current - y) / screen_height * Math.PI / 2.0;
// 	}

// 	x = x_current;
// 	y = y_current;
// }

//随机参数:颜色rgb、初速度、方位、爆炸力度、时间
let para_firework = [];

function handle_mousedown(event) {
	const x_current = event.offsetX / screen_width;

	//增加firework
	add_firework(x_current);
}


let array_color_firework_global = [];//存储颜色数据的全局数组

function add_firework(position) {
	//增加firework
	let color_firework = [];
	let color_rand = Math.random();//控制颜色选择的随机数
	let color_index = Math.floor(color_rand * (array_color_firework_global.length / 3));

	if (array_color_firework_global.length !== 0) {
		color_firework[0] = array_color_firework_global[color_index * 3];
		color_firework[1] = array_color_firework_global[color_index * 3 + 1];
		color_firework[2] = array_color_firework_global[color_index * 3 + 2];

		para_firework.push(color_firework[0], color_firework[1], color_firework[2]);

		para_firework.push(Math.random());
		para_firework.push(position);
		para_firework.push(Math.random());
		para_firework.push(0);
	}


}

//向表格增加新的行
function table_add_row(color_value) {
	const tr = document.createElement('tr');

	const td_color = document.createElement('td');
	const color_select = document.createElement('input');
	color_select.type = "color";
	color_select.value = color_value;
	td_color.appendChild(color_select);
	tr.appendChild(td_color);

	const td_button = document.createElement('td');
	const button_del = document.createElement('input');
	button_del.type = "button";
	button_del.value = "delete";
	button_del.addEventListener("click", handle_delete);
	td_button.appendChild(button_del);
	tr.appendChild(td_button);

	color_list.appendChild(tr);
}
function handle_add(event) {
	table_add_row("#ffffff");
}
//删除某一行
function handle_delete(event) {
	color_list.removeChild(this.parentNode.parentNode);
}
//将表格数据应用
function apply_color_data() {
	//清空数组
	array_color_firework_global = [];

	let nodes_list = color_list.childNodes;
	for (let i = 0; i < nodes_list.length; i += 1) {
		let color_string = nodes_list[i].firstChild.firstChild.value;
		for (let i_char = 0; i_char < 3; i_char += 1) {
			let string_tmp = color_string[i_char * 2 + 1] + color_string[i_char * 2 + 2];

			array_color_firework_global.push(parseInt(string_tmp, 16) / 255.0 * 4.0);
		}
	}
}
function handle_apply(event) {
	apply_color_data();
}

function handle_touchstart(event) {

	let touches = touchEvent.targetTouches;
	let num_touches = touches.length;

	for (let i = 0; i < num_touches; i += 1) {
		add_firework(touches[i].clientX / screen_width);
	}
}

// function handle_mouseup(event) {
// 	isclick = false;
// }

//像素大小初始化
const screen_width = window.innerWidth;
document.querySelector("#glcanvas").width = screen_width;
const screen_height = window.innerHeight;
document.querySelector("#glcanvas").height = screen_height;

//组件
const probability_range = document.querySelector("#probability");
const color_list = document.querySelector("#color_list");
document.querySelector("#add").addEventListener("click", handle_add);
document.querySelector("#apply").addEventListener("click", handle_apply);

// document.querySelector("#glcanvas").addEventListener("mousemove", handle_mousemove);
document.querySelector("#glcanvas").addEventListener("mousedown", handle_mousedown);
// document.querySelector("#glcanvas").addEventListener("mouseup", handle_mouseup);

document.querySelector("#glcanvas").addEventListener("touchstart", handle_touchstart);//触摸事件


//事件监听
document.addEventListener("DOMContentLoaded", main);